using System;
using System.Text;
using System.Net;
using System.IO;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.ComponentModel;

namespace Shine.Util.Net
{
    #region 文件信息结构
    /// <summary>
    /// 文件结构
    /// </summary>
    public struct FileStruct
    {
        /// <summary>
        /// 
        /// </summary>
        public string Flags;

        /// <summary>
        /// 
        /// </summary>
        public string Owner;

        /// <summary>
        /// 
        /// </summary>
        public string Group;

        /// <summary>
        /// 是否是目录
        /// </summary>
        public bool IsDirectory;

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateTime;

        /// <summary>
        /// 名称
        /// </summary>
        public string Name;
    }
    
    /// <summary>
    /// 操作系统文件类型
    /// </summary>
    public enum zjgisOSStyle
    {
        /// <summary>
        /// Unix
        /// </summary>
        UnixStyle,
        /// <summary>
        /// Windows
        /// </summary>
        WindowsStyle,
        /// <summary>
        /// 未知
        /// </summary>
        Unknown
    }
    #endregion
    
    /// <summary>
    /// FTP处理操作类，下载、上传文件及进度信息
    /// </summary>
    public class FTPRequest
    {
        #region 构造析构函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public FTPRequest()
        {
            this.UserName = "anonymous";  //匿名用户
            this.Password = "@anonymous";
            this._Uri = null;
            this.Proxy = null;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="uri">FTP地址：new Uri("ftp://127.0.0.1:30/")</param>
        /// <param name="userName">登录用户名</param>
        /// <param name="password">登录密码</param>
        public FTPRequest(Uri uri, string userName, string password)
        {
            this._Uri = new Uri(uri.GetLeftPart(UriPartial.Authority));
            DirectoryPath = uri.AbsolutePath;
            if (!DirectoryPath.EndsWith("/"))
                DirectoryPath += "/";
            this.UserName = userName;
            this.Password = password;
            this.Proxy = null;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="uri">FTP地址：new Uri("ftp://127.0.0.1:30/")</param>
        /// <param name="userName">登录用户名</param>
        /// <param name="password">登录密码</param>
        /// <param name="proxy">连接代理</param>
        public FTPRequest(Uri uri, string userName, string password, WebProxy proxy)
        {
            this._Uri = new Uri(uri.GetLeftPart(UriPartial.Authority));
            DirectoryPath = uri.AbsolutePath;
            if (!DirectoryPath.EndsWith("/"))
                DirectoryPath += "/";
            this.UserName = userName;
            this.Password = password;
            this.Proxy = proxy;
        }

        /// <summary>
        /// 析构函数
        /// </summary>
        ~FTPRequest()
        {
            try
            {
                if (Response != null)
                {
                    Response.Close();
                    Response = null;
                }
                if (Request != null)
                {
                    Request.Abort();
                    Request = null;
                }
            }
            catch
            {
               
            }            
        }
        #endregion

        #region 属性信息
        /// <summary>
        /// FTP请求对象
        /// </summary>
        private FtpWebRequest Request = null;

        /// <summary>
        /// FTP响应对象
        /// </summary>
        private FtpWebResponse Response = null;

        /// <summary>
        /// FTP服务器地址
        /// </summary>
        private Uri _Uri;

        /// <summary>
        /// FTP服务器地址
        /// </summary>
        public Uri Uri
        {
            get
            {
                if (DirectoryPath == "/")
                    return _Uri;
                else
                {
                    string strUri = _Uri.ToString();
                    if (strUri.EndsWith("/"))
                        strUri = strUri.Substring(0, strUri.Length - 1);
                    return new Uri(strUri + this.DirectoryPath);
                }
            }
            set
            {
                if (value.Scheme != Uri.UriSchemeFtp)
                    throw new Exception("Ftp 地址格式错误!");
                _Uri = new Uri(value.GetLeftPart(UriPartial.Authority));
                DirectoryPath = value.AbsolutePath;
                if (!DirectoryPath.EndsWith("/"))
                    DirectoryPath += "/";
            }
        }

        /// <summary>
        /// 当前工作目录
        /// </summary>
        public string DirectoryPath { get; set; }

        /// <summary>
        /// FTP登录用户
        /// </summary>
        public string UserName { get; set; }

        /// <summary>
        /// 信息
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// FTP登录密码
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// 连接FTP服务器的代理服务
        /// </summary>
        public WebProxy Proxy { get; set; }

        /// <summary>
        /// 是否需要删除临时文件
        /// </summary>
        private bool _isDeleteTempFile = false;

        /// <summary>
        /// 异步上传所临时生成的文件
        /// </summary>
        private string _UploadTempFile = "";
        #endregion

        #region 事件
        /// <summary>
        /// 文件下载进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void DownloadChanged(object sender, DownloadProgressChangedEventArgs e);

        /// <summary>
        /// 文件下载完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void DownloadCompleted(object sender, AsyncCompletedEventArgs e);

        /// <summary>
        /// 文件上传进度进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void UploadChanged(object sender, UploadProgressChangedEventArgs e);

        /// <summary>
        /// 文件上传完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void UploadCompleted(object sender, UploadFileCompletedEventArgs e);

        /// <summary>
        /// 异步下载进度发生改变触发的事件
        /// </summary>
        public event DownloadChanged Download_Changed;

        /// <summary>
        /// 异步下载文件完成之后触发的事件
        /// </summary>
        public event DownloadCompleted Download_Completed;

        /// <summary>
        /// 异步上传进度发生改变触发的事件
        /// </summary>
        public event UploadChanged Upload_Changed;

        /// <summary>
        /// 异步上传文件完成之后触发的事件
        /// </summary>
        public event UploadCompleted Upload_Completed;
        #endregion

        #region 建立连接
        /// <summary>
        /// 建立FTP链接,返回响应对象
        /// </summary>
        /// <param name="uri">FTP地址</param>
        /// <param name="mathod">操作命令</param>
        private FtpWebResponse Open(Uri uri, string mathod)
        {
            try
            {
                Request = (FtpWebRequest)WebRequest.Create(uri);
                Request.Method = mathod;
                Request.UseBinary = true;
                Request.Credentials = new NetworkCredential(this.UserName, this.Password);
                if (this.Proxy != null)
                    Request.Proxy = this.Proxy;
                return (FtpWebResponse)Request.GetResponse();
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 建立FTP链接,返回请求对象
        /// </summary>
        /// <param name="uri">FTP地址</param>
        /// <param name="mathod">操作命令</param>
        private FtpWebRequest OpenRequest(Uri uri, string mathod)
        {
            try
            {
                Request = (FtpWebRequest)WebRequest.Create(uri);
                Request.Method = mathod;
                Request.UseBinary = true;
                Request.Credentials = new NetworkCredential(this.UserName, this.Password);
                if (this.Proxy != null)
                    Request.Proxy = this.Proxy;
                return Request;
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }
        #endregion

        #region 下载文件

        /// <summary>
        /// 从FTP服务器下载文件，使用与远程文件同名的文件名来保存文件
        /// </summary>
        /// <param name="remoteFileName">远程文件名</param>
        /// <param name="localPath">本地路径</param>
        public bool DownloadFile(string remoteFileName, string localPath)
        {
            return DownloadFile(remoteFileName, localPath, remoteFileName);
        }

        /// <summary>
        /// 从FTP服务器下载文件，指定本地路径和本地文件名
        /// </summary>
        /// <param name="remoteFileName">远程文件名</param>
        /// <param name="localPath">本地路径</param>
        /// <param name="localFileName">保存本地的文件名</param>
        public bool DownloadFile(string remoteFileName, string localPath, string localFileName)
        {
            byte[] bt = null;
            try
            {
                if (!IsValidFileChars(remoteFileName) || !IsValidFileChars(localFileName) || !IsValidPathChars(localPath))
                {
                    throw new Exception("非法文件名或目录名!");
                }
                if (!Directory.Exists(localPath))
                {
                    throw new Exception("本地文件路径不存在!");
                }

                string localFullPath = Path.Combine(localPath, localFileName);
                if (File.Exists(localFullPath))
                {
                    throw new Exception("当前路径下已经存在同名文件！");
                }
                bt = DownloadFile(remoteFileName);
                if (bt != null)
                {
                    FileStream stream = new FileStream(localFullPath, FileMode.Create);
                    stream.Write(bt, 0, bt.Length);
                    stream.Flush();
                    stream.Close();
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 从FTP服务器下载文件，返回文件二进制数据
        /// </summary>
        /// <param name="remoteFileName">远程文件名</param>
        public byte[] DownloadFile(string remoteFileName)
        {
            try
            {
                if (!IsValidFileChars(remoteFileName))
                {
                    throw new Exception("非法文件名或目录名!");
                }
                Response = Open(new Uri(this.Uri.ToString() + remoteFileName), WebRequestMethods.Ftp.DownloadFile);
                Stream Reader = Response.GetResponseStream();

                MemoryStream mem = new MemoryStream(1024 * 500);
                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                int TotalByteRead = 0;
                while (true)
                {
                    bytesRead = Reader.Read(buffer, 0, buffer.Length);
                    TotalByteRead += bytesRead;
                    if (bytesRead == 0)
                        break;
                    mem.Write(buffer, 0, bytesRead);
                }
                if (mem.Length > 0)
                {
                    return mem.ToArray();
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }
        #endregion

        #region 异步下载文件
        /// <summary>
        /// 从FTP服务器异步下载文件，指定本地路径和本地文件名
        /// </summary>
        /// <param name="remoteFileName">远程文件名</param>        
        /// <param name="localPath">保存文件的本地路径,后面带有"\"</param>
        /// <param name="localFileName">保存本地的文件名</param>
        public void DownloadFileAsync(string remoteFileName, string localPath, string localFileName)
        {
            try
            {
                if (!IsValidFileChars(remoteFileName) || !IsValidFileChars(localFileName) || !IsValidPathChars(localPath))
                {
                    throw new Exception("非法文件名或目录名!");
                }
                if (!Directory.Exists(localPath))
                {
                    throw new Exception("本地文件路径不存在!");
                }

                string LocalFullPath = Path.Combine(localPath, localFileName);
                if (File.Exists(LocalFullPath))
                {
                    throw new Exception("当前路径下已经存在同名文件！");
                }
                DownloadFileAsync(remoteFileName, LocalFullPath);

            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 从FTP服务器异步下载文件，指定本地完整路径文件名
        /// </summary>
        /// <param name="RemoteFileName">远程文件名</param>
        /// <param name="LocalFullPath">本地完整路径文件名</param>
        public void DownloadFileAsync(string RemoteFileName, string LocalFullPath)
        {
            try
            {
                if (!IsValidFileChars(RemoteFileName))
                {
                    throw new Exception("非法文件名或目录名!");
                }
                if (File.Exists(LocalFullPath))
                {
                    throw new Exception("当前路径下已经存在同名文件！");
                }
                FTPWebClient client = new FTPWebClient();

                client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
                client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(client_DownloadFileCompleted);
                client.Credentials = new NetworkCredential(this.UserName, this.Password);
                if (this.Proxy != null)
                {
                    client.Proxy = this.Proxy;
                }
                client.DownloadFileAsync(new Uri(this.Uri.ToString() + RemoteFileName), LocalFullPath);
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 异步下载文件完成之后触发的事件
        /// </summary>
        /// <param name="sender">下载对象</param>
        /// <param name="e">数据信息对象</param>
        void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (Download_Completed != null)
            {
                Download_Completed(sender, e);
            }
        }

        /// <summary>
        /// 异步下载进度发生改变触发的事件
        /// </summary>
        /// <param name="sender">下载对象</param>
        /// <param name="e">进度信息对象</param>
        void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            if (Download_Changed != null)
            {
                Download_Changed(sender, e);
            }
        }
        #endregion

        #region 上传文件
        /// <summary>
        /// 创建目录并跳转到需要上传的目录，成功则返回要保存的文件名称，否则为空
        /// </summary>
        /// <param name="remoteFileName"></param>
        /// <param name="overWriteRemoteFile"></param>
        /// <returns></returns>
        private string GetRemoteName(string remoteFileName, bool overWriteRemoteFile = true)
        {
            remoteFileName = remoteFileName.Replace("\\", "/");
            if (remoteFileName.IndexOf("/") < 0) return remoteFileName;
            int idx = remoteFileName.LastIndexOf("/");
            string dir = remoteFileName.Substring(0, idx);
            string fname = remoteFileName.Substring(idx + 1, remoteFileName.Length - 1 - idx);
            if (!IsValidFileChars(fname))
            {
                Message = "非法文件名或目录名!";
                return "";
            }
            if (!CreateDirectory(dir)) return "";
            if (_ExistSubFile(fname))
            {
                if (!overWriteRemoteFile)
                {
                    Message = "FTP服务上面已经存在同名文件！";
                    return "";
                }
                Response = Open(new Uri(this.Uri.ToString() + fname), WebRequestMethods.Ftp.DeleteFile);
            }
            return fname;
        }

        /// <summary>
        /// 上传文件到FTP服务器
        /// </summary>
        /// <param name="localFullPath">本地带有完整路径的文件名</param>
        /// <param name="remoteFileName">要在FTP服务器上面保存文件名</param>
        /// <param name="overWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param>
        public bool UploadFile(string localFullPath, string remoteFileName = "", bool overWriteRemoteFile = true)
        {
            FileStream input = null;
            Stream requestStream = null;
            try
            {
                if (!File.Exists(localFullPath))
                {
                    Message = "本地文件不存在：" + localFullPath;
                    return false;
                }
                if (string.IsNullOrWhiteSpace(remoteFileName)) remoteFileName = Path.GetFileName(localFullPath);
                remoteFileName = GetRemoteName(remoteFileName, overWriteRemoteFile);
                if (string.IsNullOrWhiteSpace(remoteFileName)) return false;
                input = new FileStream(localFullPath, FileMode.Open, FileAccess.Read);
                Response = Open(new Uri(this.Uri.ToString() + remoteFileName), WebRequestMethods.Ftp.UploadFile);
                requestStream = Request.GetRequestStream();
                int bytesRead = 0;
                int TotalRead = 0;
                byte[] buffer = new byte[1024];
                while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    TotalRead += bytesRead;
                    requestStream.Write(buffer, 0, bytesRead);
                }
                input.Close();
                requestStream.Close();
                buffer = null;
                Response = (FtpWebResponse)Request.GetResponse();
                return true;
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                return false;
            }
            finally
            {
                if (input != null)
                {
                    input.Close();
                    input = null;
                }
                if (requestStream != null)
                {
                    requestStream.Close();
                    requestStream = null;
                }
            }
        }

        /// <summary>
        /// 上传文件到FTP服务器
        /// </summary>
        /// <param name="fileBytes">文件二进制内容</param>
        /// <param name="remoteFileName">要在FTP服务器上面保存文件名</param>
        /// <param name="overWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param>
        public bool UploadFile(byte[] fileBytes, string remoteFileName, bool overWriteRemoteFile = false)
        {
            if (string.IsNullOrWhiteSpace(remoteFileName))
            {
                Message = "要保存的文件名称不能为空！";
                return false;
            }
            try
            {
                remoteFileName = GetRemoteName(remoteFileName, overWriteRemoteFile);
                if (string.IsNullOrWhiteSpace(remoteFileName)) return false;
                Response = Open(new Uri(this.Uri.ToString() + remoteFileName), WebRequestMethods.Ftp.UploadFile);
                Stream requestStream = Request.GetRequestStream();
                MemoryStream mem = new MemoryStream(fileBytes);
                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                int TotalRead = 0;
                while (true)
                {
                    bytesRead = mem.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break;
                    TotalRead += bytesRead;
                    requestStream.Write(buffer, 0, bytesRead);
                }
                requestStream.Close();
                Response = (FtpWebResponse)Request.GetResponse();
                mem.Close();
                mem.Dispose();
                fileBytes = null;
                return true;
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        #endregion

        #region 异步上传文件
        /// <summary>
        /// 异步上传文件到FTP服务器
        /// </summary>
        /// <param name="localFullPath">本地带有完整路径的文件名</param>
        public void UploadFileAsync(string localFullPath)
        {
            UploadFileAsync(localFullPath, Path.GetFileName(localFullPath), false);
        }

        /// <summary>
        /// 异步上传文件到FTP服务器
        /// </summary>
        /// <param name="localFullPath">本地带有完整路径的文件</param>
        /// <param name="overWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param>
        public void UploadFileAsync(string localFullPath, bool overWriteRemoteFile)
        {
            UploadFileAsync(localFullPath, Path.GetFileName(localFullPath), overWriteRemoteFile);
        }

        /// <summary>
        /// 异步上传文件到FTP服务器
        /// </summary>
        /// <param name="localFullPath">本地带有完整路径的文件</param>
        /// <param name="remoteFileName">要在FTP服务器上面保存文件名</param>
        public void UploadFileAsync(string localFullPath, string remoteFileName)
        {
            UploadFileAsync(localFullPath, remoteFileName, false);
        }

        /// <summary>
        /// 异步上传文件到FTP服务器
        /// </summary>
        /// <param name="localFullPath">本地带有完整路径的文件名</param>
        /// <param name="remoteFileName">要在FTP服务器上面保存文件名</param>
        /// <param name="overWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param>
        public void UploadFileAsync(string localFullPath, string remoteFileName, bool overWriteRemoteFile)
        {
            if (string.IsNullOrWhiteSpace(remoteFileName))
                remoteFileName = Path.GetFileName(localFullPath);
            if (remoteFileName.IndexOf("/") > 0)
            {
                int idx = remoteFileName.LastIndexOf("/");
                string dir = remoteFileName.Substring(0, idx);
                if (!CreateDirectory(dir))
                {
                    throw new Exception("目录创建失败");
                }
                GotoDirectory(dir);
                remoteFileName = remoteFileName.Substring(idx + 1, remoteFileName.Length - 1 - idx);
            }
            try
            {
                if (!IsValidFileChars(remoteFileName) || !IsValidFileChars(Path.GetFileName(localFullPath)) || !IsValidPathChars(Path.GetDirectoryName(localFullPath)))
                {
                    throw new Exception("非法文件名或目录名!");
                }
                if (!overWriteRemoteFile && ExistFile(remoteFileName))
                {
                    throw new Exception("FTP服务上面已经存在同名文件！");
                }
                if (File.Exists(localFullPath))
                {
                    FTPWebClient client = new FTPWebClient();

                    client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged);
                    client.UploadFileCompleted += new UploadFileCompletedEventHandler(client_UploadFileCompleted);
                    client.Credentials = new NetworkCredential(this.UserName, this.Password);
                    if (this.Proxy != null)
                    {
                        client.Proxy = this.Proxy;
                    }
                    client.UploadFileAsync(new Uri(this.Uri.ToString() + remoteFileName), localFullPath);

                }
                else
                {
                    throw new Exception("本地文件不存在!");
                }
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 异步上传文件到FTP服务器
        /// </summary>
        /// <param name="FileBytes">上传的二进制数据</param>
        /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param>
        public void UploadFileAsync(byte[] FileBytes, string RemoteFileName)
        {
            if (!IsValidFileChars(RemoteFileName))
            {
                throw new Exception("非法文件名或目录名!");
            }
            UploadFileAsync(FileBytes, RemoteFileName, false);
        }

        /// <summary>
        /// 异步上传文件到FTP服务器
        /// </summary>
        /// <param name="FileBytes">文件二进制内容</param>
        /// <param name="RemoteFileName">要在FTP服务器上面保存文件名</param>
        /// <param name="OverWriteRemoteFile">是否覆盖远程服务器上面同名的文件</param>
        public void UploadFileAsync(byte[] FileBytes, string RemoteFileName, bool OverWriteRemoteFile)
        {
            try
            {

                if (!IsValidFileChars(RemoteFileName))
                {
                    throw new Exception("非法文件名！");
                }
                if (!OverWriteRemoteFile && ExistFile(RemoteFileName))
                {
                    throw new Exception("FTP服务上面已经存在同名文件！");
                }
                string TempPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Templates);
                if (!TempPath.EndsWith("\\"))
                {
                    TempPath += "\\";
                }
                string TempFile = TempPath + Path.GetRandomFileName();
                TempFile = Path.ChangeExtension(TempFile, Path.GetExtension(RemoteFileName));
                FileStream Stream = new FileStream(TempFile, FileMode.CreateNew, FileAccess.Write);
                Stream.Write(FileBytes, 0, FileBytes.Length);   //注意，因为Int32的最大限制，最大上传文件只能是大约2G多一点
                Stream.Flush();
                Stream.Close();
                Stream.Dispose();
                _isDeleteTempFile = true;
                _UploadTempFile = TempFile;
                FileBytes = null;
                UploadFileAsync(TempFile, RemoteFileName, OverWriteRemoteFile);

            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 异步上传文件完成之后触发的事件
        /// </summary>
        /// <param name="sender">下载对象</param>
        /// <param name="e">数据信息对象</param>
        void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
        {
            if (_isDeleteTempFile)
            {
                if (File.Exists(_UploadTempFile))
                {
                    File.SetAttributes(_UploadTempFile, FileAttributes.Normal);
                    File.Delete(_UploadTempFile);
                }
                _isDeleteTempFile = false;
            }
            if (Upload_Completed != null)
            {
                Upload_Completed(sender, e);
            }
        }

        /// <summary>
        /// 异步上传进度发生改变触发的事件
        /// </summary>
        /// <param name="sender">下载对象</param>
        /// <param name="e">进度信息对象</param>
        void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
        {
            if (Upload_Changed != null)
            {
                Upload_Changed(sender, e);
            }
        }
        #endregion

        #region 列出目录文件信息
        /// <summary>
        /// 列出FTP服务器上面当前目录的所有文件和目录
        /// </summary>
        public List<FileStruct> ListFilesAndDirectories()
        {
            Response = Open(this.Uri, WebRequestMethods.Ftp.ListDirectoryDetails);
            StreamReader stream = new StreamReader(Response.GetResponseStream(), Encoding.Default);
            string datastring = stream.ReadToEnd();
            if (string.IsNullOrWhiteSpace(datastring)) return null;
            List<FileStruct> list = GetList(datastring);
            return list;
        }

        /// <summary>
        /// 列出FTP服务器上面当前目录的所有文件
        /// </summary>
        public List<FileStruct> ListFiles()
        {
            List<FileStruct> listAll = ListFilesAndDirectories();
            if (listAll == null || listAll.Count == 0) return null;
            return listAll.FindAll(t => !t.IsDirectory);
        }

        /// <summary>
        /// 列出FTP服务器上面当前目录的所有的目录
        /// </summary>
        public List<FileStruct> ListDirectories()
        {
            List<FileStruct> listAll = ListFilesAndDirectories();
            if (listAll == null || listAll.Count == 0) return null;
            return listAll.FindAll(t => t.IsDirectory);
        }

        /// <summary>
        /// 获得文件和目录列表
        /// </summary>
        /// <param name="datastring">FTP返回的列表字符信息</param>
        private List<FileStruct> GetList(string datastring)
        {
            List<FileStruct> myListArray = new List<FileStruct>();
            string[] dataRecords = datastring.Split('\n');
            zjgisOSStyle _osStyle = GuessFileListStyle(dataRecords);
            foreach (string s in dataRecords)
            {
                if (_osStyle != zjgisOSStyle.Unknown && !string.IsNullOrWhiteSpace(s))
                {
                    FileStruct f = new FileStruct();
                    f.Name = "..";
                    switch (_osStyle)
                    {
                        case zjgisOSStyle.UnixStyle:
                            f = ParseFileStructFromUnixStyleRecord(s);
                            break;
                        case zjgisOSStyle.WindowsStyle:
                            f = ParseFileStructFromWindowsStyleRecord(s);
                            break;
                    }
                    if (!(f.Name == "." || f.Name == ".."))
                    {
                        myListArray.Add(f);
                    }
                }
            }
            return myListArray;
        }

        /// <summary>
        /// 判断文件列表的方式Window方式还是Unix方式
        /// </summary>
        /// <param name="recordList">文件信息列表</param>
        private zjgisOSStyle GuessFileListStyle(string[] recordList)
        {
            foreach (string s in recordList)
            {
                if (s.Length > 10 && Regex.IsMatch(s.Substring(0, 10), "(-|d)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)(-|r)(-|w)(-|x)"))
                {
                    return zjgisOSStyle.UnixStyle;
                }
                else if (s.Length > 8 && Regex.IsMatch(s.Substring(0, 8), "[0-9][0-9]-[0-9][0-9]-[0-9][0-9]"))
                {
                    return zjgisOSStyle.WindowsStyle;
                }
            }
            return zjgisOSStyle.Unknown;
        }

        /// <summary>
        /// 从Windows格式中返回文件信息
        /// </summary>
        /// <param name="record">文件信息</param>
        private FileStruct ParseFileStructFromWindowsStyleRecord(string record)
        {
            FileStruct f = new FileStruct();
            string processstr = record.Trim();
            string dateStr = processstr.Substring(0, 8);
            processstr = (processstr.Substring(8, processstr.Length - 8)).Trim();
            string timeStr = processstr.Substring(0, 7);
            processstr = (processstr.Substring(7, processstr.Length - 7)).Trim();
            DateTimeFormatInfo myDTFI = new CultureInfo("en-US", false).DateTimeFormat;
            myDTFI.ShortTimePattern = "t";
            f.CreateTime = DateTime.Parse(dateStr + " " + timeStr, myDTFI);
            if (processstr.Substring(0, 5) == "<DIR>")
            {
                f.IsDirectory = true;
                processstr = (processstr.Substring(5, processstr.Length - 5)).Trim();
            }
            else
            {
                string[] strs = processstr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);   // true);
                processstr = strs[1];
                f.IsDirectory = false;
            }
            f.Name = processstr;
            return f;
        }

        /// <summary>
        /// 从Unix格式中返回文件信息
        /// </summary>
        /// <param name="record">文件信息</param>
        private FileStruct ParseFileStructFromUnixStyleRecord(string record)
        {
            FileStruct f = new FileStruct();
            string processstr = record.Trim();
            f.Flags = processstr.Substring(0, 10);
            f.IsDirectory = (f.Flags[0] == 'd');
            processstr = (processstr.Substring(11)).Trim();
            _cutSubstringFromStringWithTrim(ref processstr, ' ', 0);   //跳过一部分
            f.Owner = _cutSubstringFromStringWithTrim(ref processstr, ' ', 0);
            f.Group = _cutSubstringFromStringWithTrim(ref processstr, ' ', 0);
            _cutSubstringFromStringWithTrim(ref processstr, ' ', 0);   //跳过一部分
            string yearOrTime = processstr.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[2];
            if (yearOrTime.IndexOf(":") >= 0)  //time
            {
                processstr = processstr.Replace(yearOrTime, DateTime.Now.Year.ToString());
            }
            f.CreateTime = DateTime.Parse(_cutSubstringFromStringWithTrim(ref processstr, ' ', 8));
            f.Name = processstr;   //最后就是名称
            return f;
        }

        /// <summary>
        /// 按照一定的规则进行字符串截取
        /// </summary>
        /// <param name="s">截取的字符串</param>
        /// <param name="c">查找的字符</param>
        /// <param name="startIndex">查找的位置</param>
        private string _cutSubstringFromStringWithTrim(ref string s, char c, int startIndex)
        {
            int pos1 = s.IndexOf(c, startIndex);
            string retString = s.Substring(0, pos1);
            s = (s.Substring(pos1)).Trim();
            return retString;
        }
        #endregion

        #region 删除文件

        /// <summary>
        /// 删除同名的文件
        /// </summary>
        /// <param name="fileName">要删除的文件名，不带后缀，若为相对路径的文件时，第一个为【.】，即【./1/2/3】</param>
        public void DeleteSameFile(string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName)) return;
            fileName = fileName.Replace("\\", "/");
            try
            {
                if (fileName.IndexOf("/") > 0)
                {
                    int idx = fileName.LastIndexOf("/");
                    string dir = fileName.Substring(0, idx);
                    fileName = fileName.Substring(idx + 1, fileName.Length - 1 - idx);
                    if (!ExistDirectory(dir)) return;
                }
                if (!IsValidFileChars(fileName))
                {
                    throw new Exception("文件名非法！");
                }
                List<FileStruct> listFile = ListFiles();
                if (listFile == null || listFile.Count == 0) return ;
                foreach (FileStruct file in listFile)
                {
                    int idx = file.Name.LastIndexOf(".");
                    string fname = file.Name.Substring(0, idx);
                    if (fname.Equals(fileName, StringComparison.CurrentCultureIgnoreCase))
                    {
                        Response = Open(new Uri(this.Uri.ToString() + file.Name), WebRequestMethods.Ftp.DeleteFile);
                    }
                }
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 从FTP服务器上面删除一个文件
        /// </summary>
        /// <param name="fileName">要删除的文件名,若为相对路径的文件时，第一个为【.】，即【./1/2/3.txt】</param>
        public void DeleteFile(string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName)) return ;
            if (!ExistFile(fileName)) return ;
            try
            {
                if (fileName.IndexOf("/") > 0)
                {
                    int idx = fileName.LastIndexOf("/");
                    fileName = fileName.Substring(idx + 1, fileName.Length - 1 - idx);
                }
                if (!IsValidFileChars(fileName))
                {
                    throw new Exception("文件名非法！");
                }
                if (!IsValidFileChars(fileName))
                {
                    throw new Exception("文件名非法！");
                }
                Response = Open(new Uri(this.Uri.ToString() + fileName), WebRequestMethods.Ftp.DeleteFile);
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }
        #endregion

        #region 重命名文件
        /// <summary>
        /// 更改一个文件的名称或一个目录的名称
        /// </summary>
        /// <param name="RemoteFileName">原始文件或目录名称</param>
        /// <param name="NewFileName">新的文件或目录的名称</param>
        public bool ReName(string RemoteFileName, string NewFileName)
        {
            try
            {
                if (!IsValidFileChars(RemoteFileName) || !IsValidFileChars(NewFileName))
                {
                    throw new Exception("文件名非法！");
                }
                if (RemoteFileName == NewFileName)
                {
                    return true;
                }
                if (ExistFile(RemoteFileName))
                {
                    Request = OpenRequest(new Uri(this.Uri.ToString() + RemoteFileName), WebRequestMethods.Ftp.Rename);
                    Request.RenameTo = NewFileName;
                    Response = (FtpWebResponse)Request.GetResponse();

                }
                else
                {
                    throw new Exception("文件在服务器上不存在！");
                }
                return true;
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }
        #endregion

        #region 拷贝、移动文件
        /// <summary>
        /// 把当前目录下面的一个文件拷贝到服务器上面另外的目录中，注意，拷贝文件之后，当前工作目录还是文件原来所在的目录
        /// </summary>
        /// <param name="RemoteFile">当前目录下的文件名</param>
        /// <param name="DirectoryName">新目录名称。
        /// 说明：如果新目录是当前目录的子目录，则直接指定子目录。如: SubDirectory1/SubDirectory2 ；
        /// 如果新目录不是当前目录的子目录，则必须从根目录一级一级的指定。如： ./NewDirectory/SubDirectory1/SubDirectory2
        /// </param>
        /// <returns></returns>
        public bool CopyFileToAnotherDirectory(string RemoteFile, string DirectoryName)
        {
            string CurrentWorkDir = this.DirectoryPath;
            try
            {
                byte[] bt = DownloadFile(RemoteFile);
                GotoDirectory(DirectoryName);
                bool Success = UploadFile(bt, RemoteFile, false);
                this.DirectoryPath = CurrentWorkDir;
                return Success;
            }
            catch (Exception ep)
            {
                this.DirectoryPath = CurrentWorkDir;
                Message = ep.ToString();
                throw ep;
            }
        }
        /// <summary>
        /// 把当前目录下面的一个文件移动到服务器上面另外的目录中，注意，移动文件之后，当前工作目录还是文件原来所在的目录
        /// </summary>
        /// <param name="RemoteFile">当前目录下的文件名</param>
        /// <param name="DirectoryName">新目录名称。
        /// 说明：如果新目录是当前目录的子目录，则直接指定子目录。如: SubDirectory1/SubDirectory2 ；
        /// 如果新目录不是当前目录的子目录，则必须从根目录一级一级的指定。如： ./NewDirectory/SubDirectory1/SubDirectory2
        /// </param>
        /// <returns></returns>
        public bool MoveFileToAnotherDirectory(string RemoteFile, string DirectoryName)
        {
            string CurrentWorkDir = this.DirectoryPath;
            try
            {
                if (DirectoryName == "")
                    return false;
                if (!DirectoryName.StartsWith("/"))
                    DirectoryName = "/" + DirectoryName;
                if (!DirectoryName.EndsWith("/"))
                    DirectoryName += "/";
                bool Success = ReName(RemoteFile, DirectoryName + RemoteFile);
                this.DirectoryPath = CurrentWorkDir;
                return Success;
            }
            catch (Exception ep)
            {
                this.DirectoryPath = CurrentWorkDir;
                Message = ep.ToString();
                throw ep;
            }
        }
        #endregion

        #region 目录切换操作
        /// <summary>
        /// 进入一个目录
        /// </summary>
        /// <param name="directoryName">
        /// 新目录的名字。 
        /// 说明：如果新目录是当前目录的子目录，则直接指定子目录。如: SubDirectory1/SubDirectory2 ； 
        /// 如果新目录不是当前目录的子目录，则必须从根目录一级一级的指定。如： ./NewDirectory/SubDirectory1/SubDirectory2
        /// </param>
        public bool GotoDirectory(string directoryName)
        {
            string currentWorkPath = this.DirectoryPath;
            try
            {
                directoryName = directoryName.Replace("\\", "/");
                string[] directoryNames = directoryName.Split(new char[] { '/' });
                if (directoryNames[0] == ".")
                {
                    this.DirectoryPath = "/";
                    if (directoryNames.Length == 1) return true;
                    Array.Clear(directoryNames, 0, 1);
                }
                foreach (string dir in directoryNames)
                {
                    if (string.IsNullOrWhiteSpace(dir)) continue;
                    if (!GotoSubDirectory(dir))
                    {
                        this.DirectoryPath = currentWorkPath;
                        return false;
                    }
                }
                return true;
            }
            catch (Exception ep)
            {
                this.DirectoryPath = currentWorkPath;
                Message = ep.ToString();
                return false;
            }
        }

        /// <summary>
        /// 从当前工作目录进入一个子目录
        /// </summary>
        /// <param name="directoryName">子目录名称</param>
        public bool GotoSubDirectory(string directoryName)
        {
            if (string.IsNullOrWhiteSpace(directoryName)) return true;
            try
            {
                if (directoryName.IndexOf("/") >= 0 || !IsValidPathChars(directoryName))
                {
                    Message = "目录名非法!";
                    return false;
                }
                if (directoryName.Length > 0 && _ExistSubDirectory(directoryName))
                {
                    if (!directoryName.EndsWith("/")) directoryName += "/";
                    DirectoryPath += directoryName;
                    return true;
                }
                return false;
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                return false;
            }
        }

        /// <summary>
        /// 从当前工作目录往上一级目录
        /// </summary>
        public bool ComeoutDirectory()
        {
            if (DirectoryPath == "/")
            {
                Message = "当前目录已经是根目录！";
                return true;
            }
            char[] sp = new char[1] { '/' };
            string[] strDir = DirectoryPath.Split(sp, StringSplitOptions.RemoveEmptyEntries);
            if (strDir.Length == 1)
            {
                DirectoryPath = "/";
            }
            else
            {
                DirectoryPath = String.Join("/", strDir, 0, strDir.Length - 1);
            }
            return true;

        }
        #endregion

        #region 目录或文件存在的判断
        /// <summary>
        /// 判断当前目录下指定的子目录是否存在，若存在则跳转到指定的目录中
        /// </summary>
        /// <param name="directoryName">新目录的名字。 
        /// 说明：如果新目录是当前目录的子目录，则直接指定子目录。如: SubDirectory1/SubDirectory2 ； 
        /// 如果新目录不是当前目录的子目录，则必须从根目录一级一级的指定。如： ./NewDirectory/SubDirectory1/SubDirectory2
        /// </param>
        public bool ExistDirectory(string directoryName)
        {
            string currentWorkPath = this.DirectoryPath;
            try
            {
                directoryName = directoryName.Replace("\\", "/");
                string[] directoryNames = directoryName.Split(new char[] { '/' });
                if (directoryNames[0] == ".")
                {
                    this.DirectoryPath = "/";
                    if (directoryNames.Length == 1) return true;
                    Array.Clear(directoryNames, 0, 1);
                }
                foreach (string dir in directoryNames)
                {
                    if (string.IsNullOrWhiteSpace(dir)) continue;
                    if (!IsValidPathChars(dir) || !_ExistSubDirectory(dir))
                    {
                        Message = "目录【" + dir + "】不存在，或不是有效的目录名称";
                        return false;
                    }
                    if (!GotoSubDirectory(dir))
                    {
                        this.DirectoryPath = currentWorkPath;
                        return false;
                    }
                }
                return true;
            }
            catch (Exception ep)
            {
                this.DirectoryPath = currentWorkPath;
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 判断当前目录下指定的子目录是否存在
        /// </summary>
        /// <param name="directoryName">指定的目录名</param>
        public bool ExistSubDirectory(string directoryName)
        {
            try
            {
                if (!IsValidPathChars(directoryName))
                {
                    throw new Exception("目录名非法！");
                }
                return _ExistSubDirectory(directoryName);
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 判断当前目录下指定的子目录是否存在
        /// </summary>
        /// <param name="directoryName">指定的目录名</param>
        private bool _ExistSubDirectory(string directoryName)
        {
            List<FileStruct> listDir = ListDirectories();
            if (listDir == null || listDir.Count == 0) return false;
            foreach (FileStruct name in listDir)
            {
                if (name.Name.Equals(directoryName, StringComparison.CurrentCultureIgnoreCase))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// 判断服务器上当前目录或根相对目录下是否存在指定的文件
        /// </summary>
        /// <param name="fileName">服务器上的文件名称或文件相对路径名称：如1.txt;./dir/1.txt</param>
        public bool ExistFile(string fileName)
        {
            if (string.IsNullOrWhiteSpace(fileName)) return false;
            fileName = fileName.Replace("\\", "/");
            try
            {
                if (fileName.IndexOf("/") > 0)
                {
                    int idx = fileName.LastIndexOf("/");
                    string dir = fileName.Substring(0, idx);
                    fileName = fileName.Substring(idx + 1, fileName.Length - 1 - idx);
                    if (!ExistDirectory(dir)) return false;
                }
                if (!IsValidFileChars(fileName))
                {
                    throw new Exception("文件名非法！");
                }
                return _ExistSubFile(fileName);
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 判断服务器上当前目录下是否指定的文件
        /// </summary>
        /// <param name="fileName">服务器上的文件名称</param>
        /// <returns></returns>
        public bool ExistSubFile(string fileName)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(fileName) || !IsValidFileChars(fileName))
                    throw new Exception("文件名称为空或文件名非法！");
                return _ExistSubFile(fileName);
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }

        /// <summary>
        /// 判断服务器上当前目录是否存在指定的文件
        /// </summary>
        /// <param name="fileName">服务器上的文件名称</param>
        private bool _ExistSubFile(string fileName)
        {
            List<FileStruct> listFile = ListFiles();
            if (listFile == null || listFile.Count == 0) return false;
            foreach (FileStruct file in listFile)
            {
                if (file.Name.Equals(fileName, StringComparison.CurrentCultureIgnoreCase))
                    return true;
            }
            return false;
        }

        #endregion

        #region 建立、删除子目录

        /// <summary>
        /// 在服务器上指定的目录中创建子目录。成功则定位到创建的目录中
        /// </summary>
        /// <param name="directoryName">
        /// 新目录的名字。 
        /// 说明：如果新目录是当前目录的子目录，则直接指定子目录。如: SubDirectory1/SubDirectory2 ； 
        /// 如果新目录不是当前目录的子目录，则必须从根目录一级一级的指定。如： ./NewDirectory/SubDirectory1/SubDirectory2
        /// </param>
        /// <returns></returns>
        public bool CreateDirectory(string directoryName)
        {
            string currentWorkPath = this.DirectoryPath;
            try
            {
                directoryName = directoryName.Replace("\\", "/");
                string[] directoryNames = directoryName.Split(new char[] { '/' });
                if (directoryNames[0] == ".")
                {
                    this.DirectoryPath = "/";
                    if (directoryNames.Length == 1) return true;
                    Array.Clear(directoryNames, 0, 1);
                }
                foreach (string dir in directoryNames)
                {
                    if (string.IsNullOrWhiteSpace(dir)) continue;
                    if (!CreateSubDirectory(dir))
                    {
                        this.DirectoryPath = currentWorkPath;
                        return false;
                    }
                    if (!GotoSubDirectory(dir))
                    {
                        this.DirectoryPath = currentWorkPath;
                        return false;
                    }
                }
                return true;
            }
            catch (Exception ep)
            {
                this.DirectoryPath = currentWorkPath;
                Message = ep.ToString();
                return false;
            }
        }

        /// <summary>
        /// 在FTP服务器上当前工作目录建立一个子目录
        /// </summary>
        /// <param name="directoryName">子目录名称</param>
        public bool CreateSubDirectory(string directoryName)
        {
            try
            {
                Message = "";
                if (!IsValidPathChars(directoryName))
                {
                    Message = "目录名非法！";
                    return false;
                }
                if (_ExistSubDirectory(directoryName))
                {
                    Message = "目录已存在";
                    return true;
                }
                Response = Open(new Uri(this.Uri.ToString() + directoryName), WebRequestMethods.Ftp.MakeDirectory);
                return true;
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                return false;
            }
        }

        /// <summary>
        /// 从当前工作目录中删除一个子目录
        /// </summary>
        /// <param name="DirectoryName">子目录名称</param>
        public bool RemoveDirectory(string DirectoryName)
        {
            try
            {
                if (!IsValidPathChars(DirectoryName))
                {
                    Message = "目录名非法！";
                    return false;
                }
                if (!ExistSubDirectory(DirectoryName))
                {
                    Message = "服务器上面不存在指定的文件名或目录名！";
                    return false;
                }
                Response = Open(new Uri(this.Uri.ToString() + DirectoryName), WebRequestMethods.Ftp.RemoveDirectory);
                return true;
            }
            catch (Exception ep)
            {
                Message = ep.ToString();
                throw ep;
            }
        }
        #endregion

        #region 文件、目录名称有效性判断
        /// <summary>
        /// 判断目录名中字符是否合法
        /// </summary>
        /// <param name="directoryName">目录名称</param>
        public bool IsValidPathChars(string directoryName)
        {
            char[] invalidPathChars = Path.GetInvalidPathChars();
            char[] DirChar = directoryName.ToCharArray();
            foreach (char C in DirChar)
            {
                if (Array.BinarySearch(invalidPathChars, C) >= 0)
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 判断文件名中字符是否合法
        /// </summary>
        /// <param name="fileName">文件名称</param>
        public bool IsValidFileChars(string fileName)
        {
            char[] invalidFileChars = Path.GetInvalidFileNameChars();
            char[] NameChar = fileName.ToCharArray();
            foreach (char C in NameChar)
            {
                if (Array.BinarySearch(invalidFileChars, C) >= 0)
                {
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region 重载WebClient，支持FTP进度
        /// <summary>
        /// 重载WebClient，支持FTP进度
        /// </summary>
        internal class FTPWebClient : WebClient
        {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="address"></param>
            /// <returns></returns>
            protected override WebRequest GetWebRequest(Uri address)
            {
                FtpWebRequest req = (FtpWebRequest)base.GetWebRequest(address);
                req.UsePassive = false;
                return req;
            }
        }
        #endregion
    }

}